import React from 'react';
import _ from 'lodash';
import classNames from 'classnames';
import { ITextValuePair } from '../sys';

let checkBoxSeq = 0;

const nextCheckBoxId = (): string => 'cb' + (checkBoxSeq++);

interface ICheckBoxProps extends React.InputHTMLAttributes<HTMLInputElement>, React.ClassAttributes<CheckBox> {
    inline?: boolean,
    labelText?: string,
}

class CheckBox extends React.Component<ICheckBoxProps, boolean>{
    private inputRef: React.RefObject<HTMLInputElement>;

    constructor(props: ICheckBoxProps) {
        super(props);
        this.state = props.checked;
        this.inputRef = React.createRef();
    }

    static defultProps: ICheckBoxProps = {
        type: 'checkbox',
        className: 'field',
        inline: true,
    };

    setChecked = (value?: boolean): CheckBox => {
        if (this.inputRef.current) { this.inputRef.current.checked = value; }

        return this;
    };

    isChecked = (): boolean => this.inputRef.current ? this.inputRef.current.checked : false;

    shouldComponentUpdate = (nextProps: ICheckBoxProps): boolean =>
        !_.isEqual(nextProps.labelText, this.props.labelText)
        || !_.isEqual(nextProps.defaultValue, this.props.defaultValue)
        || this.props.defaultChecked !== nextProps.defaultChecked;

    render = (): JSX.Element => {
        const { className, labelText: labelText_, inline, ref, ...restProps } = this.props;
        const labelText = _.trim(labelText_);
        const id = nextCheckBoxId();

        return <div className={classNames(className, { inline })}>
            <div className="ui checkbox">
                <input id={id} ref={this.inputRef} type="checkbox" {...restProps} className={classNames({ hidden: labelText })} />
                {labelText && (<label htmlFor={id} >{labelText}</label>)}
            </div >
        </div>;
    }
};

interface ICheckBoxGroupProps extends React.HTMLAttributes<HTMLElement>, React.ClassAttributes<CheckBoxGroup> {
    inline?: boolean,
    labelText?: string,
    options?: ITextValuePair[],
    checked: any[],
}

/**
 * 复选框组。通过定义`options`属性，创建一组复选框。`option.text`是复选框的文本，`option.value`是复选框的值。
 */
class CheckBoxGroup extends React.Component<ICheckBoxGroupProps> {
    inputRefs: Array<React.RefObject<HTMLInputElement>>;

    constructor(props: ICheckBoxGroupProps) {
        super(props);

        this.inputRefs = [];
    }

    static defaultProps: ICheckBoxGroupProps = {
        inline: true,
        className: 'field',
        labelText: '',
        checked: [],
    };

    getValue = (): string[] => this.inputRefs.filter(ref => ref.current && ref.current.checked).map(ref => ref.current.value);

    setValue = (value: any[]): CheckBoxGroup => {
        const value_ = _.map(value, v => v ? v.toString() : '');
        this.inputRefs.forEach(inputRef => {
            if (inputRef.current) {
                inputRef.current.checked = _.indexOf(value_, inputRef.current.value) >= 0;
            }
        });
        return this;
    };

    private newRef = (): React.RefObject<HTMLInputElement> => {
        const ref = React.createRef<HTMLInputElement>();
        this.inputRefs.push(ref);
        return ref;
    };

    shouldComponentUpdate = (nextProps: ICheckBoxGroupProps): boolean =>
        !_.isEqual(nextProps.labelText, this.props.labelText)
        || !_.isEqual(this.props.options, nextProps.options)
        || !_.isEqual(this.props.checked, nextProps.checked);

    render = (): JSX.Element => {
        const { labelText, className, checked, options, onChange, inline, ref, ...restProps } = this.props;
        const checkBoxes: JSX.Element[] = _.map(options, (entry: ITextValuePair) => {
            const id = nextCheckBoxId();
            return <div className="ui checkbox" style={{ marginRight: '1em' }} key={entry.value}>
                <input id={id} type="checkbox" defaultValue={entry.value} className="hidden"
                    defaultChecked={_.indexOf(this.props.checked, entry.value) >= 0}
                    ref={this.newRef()} {...restProps} />
                <label htmlFor={id} >{entry.text}</label>
            </div>;
        });
        return <div className={classNames(className, { inline, grouped: !inline })} {...restProps}>
            {labelText && (<label style={{ wordBreak: 'keep-all' }} >{labelText}</label>)}
            {checkBoxes}
        </div>;
    }
}

export { CheckBox, CheckBoxGroup };